package com.nononsenseapps.feeder.model

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.*
import com.gitee.wsl.ext.base.isFalse
import com.gitee.wsl.ext.base.loop
import com.gitee.wsl.android.store.statehandle.saveAble
import com.nononsenseapps.feeder.db.FEED_ITEM_TAG_ROOT_NAME
import com.nononsenseapps.feeder.db.UIState
import com.nononsenseapps.feeder.db.entity.FeedItemTag
import com.nononsenseapps.feeder.db.entity.FeedRule
import com.nononsenseapps.feeder.db.room.*
import com.nononsenseapps.feeder.db.view.PreviewItem
import com.nononsenseapps.feeder.util.PrefUtils
import io.noties.markwon.base.html.MarkwonHtmlParserFormatImpl
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import timber.log.Timber

val htmlParser by lazy{
    MarkwonHtmlParserFormatImpl.create(
        MarkwonHtmlParserFormatImpl.SampleBlockHandler())
}


class GlobalViewModel(application: Application, private val savedStateHandle: SavedStateHandle) : AndroidViewModel(application){

     val feedItemFeatureDao by lazy {  AppDatabase.getInstance(application).feedItemFeatureDao() }

     val feedRuleDao by lazy { AppDatabase.getInstance(application).feedRuleDao()}

     val feedItemTagDao by lazy { AppDatabase.getInstance(application).feedItemTagDao()}

     val feedItemDao by lazy { AppDatabase.getInstance(application).feedItemDao()}

     val feedDao by lazy { AppDatabase.getInstance(application).feedDao()  }

    var currentItemList:List<PreviewItem>?=null

    var lastUndoReadItemID by savedStateHandle.saveAble<Long>(UIState.GLOBAL.LAST_UNDO_READ_ITEM_ID)

    var currentItem : PreviewItem?=null
    var leftItem : PreviewItem?=null
    var rightItem : PreviewItem?=null


    val hotFeedList = MutableLiveData(PrefUtils.getHotFeedList(application))

    val reverseListOrder by lazy {  MutableLiveData(PrefUtils.reverseItemListOrder(context = application))}

    init{
        Timber.d("GlobalViewModel init ....")
    }

    fun feedItemFeatureList() = feedItemFeatureDao.listFeedItemFeature()

    fun changeCurrentItemList(itemList:List<PreviewItem>){
        currentItemList = itemList
        initNavigateItems()
    }

    fun changeCurrentItem(item: PreviewItem){
        Timber.d("changeCurrentItem before:${currentItem?.id} \t item:${item.id}")
        currentItem=item
        lastUndoReadItemID=item.id
        initNavigateItems()
    }

    fun changeListItemOrder(reverse:Boolean=true){
        reverseListOrder.value= reverse
        PrefUtils.setReverseListOrder(context =getApplication(),order = reverse)
    }

    fun nextItemId():Long?{
        val next=if(reverseListOrder.value!!)  leftItem else rightItem
        next?.let { changeCurrentItem(it) }
        return next?.id
    }

    fun prefItemId():Long?{
        val pref=if(reverseListOrder.value!!)  rightItem else leftItem
        pref?.let{ changeCurrentItem(it) }
        return pref?.id
    }

    fun nextItem(): PreviewItem?{
        currentItemList?.let {list->
            currentItem?.let {item->
                val index = list.indexOf(item)
                if (index < list.size - 1)
                    return list[index + 1]
            }
        }
        return null
    }

    fun prefItem(): PreviewItem?{
        currentItemList?.let { list ->
            currentItem?.let {item->
                val index = list.indexOf(item)
                if (index > 0)
                    return list[index - 1]
            }
        }
        return null
    }

    fun currentItemId():Long{
        return currentItem?.id?: ID_UNSET
    }

    fun updateHotFeedList(newHotFeedList:List<Long>){
        PrefUtils.setHotFeedList(getApplication(),newHotFeedList)
        hotFeedList.postValue(newHotFeedList)
    }

    @SuppressLint("SuspiciousIndentation")
    fun createCurrentListItemsTags():List<String>{
        val retList= mutableSetOf<String>()
           loop{
               currentItemList?.forEachIndexed { _, item ->
                   item.itemTags.split(",").forEach {
                       retList.add(it)
                       if (retList.size > 10)
                           return@loop
                   }
               }
           }
        retList.remove("")
        return retList.toList()
    }

    fun initNavigateItems() {
        if(currentItemList!=null&&currentItem!=null) {
            leftItem = prefItem()
            rightItem = nextItem()
        }
    }

    fun checkNavigateItems(){
        currentItemList?.let { list ->
            if (currentItem != null) {
                if (list.contains(currentItem))
                    currentItem?.let {changeCurrentItem(it)}
                else {
                    leftItem?.let { list.contains(it).isFalse { leftItem = null } }
                    rightItem?.let { list.contains(it).isFalse  { rightItem = null } }
                }
            }else{
                leftItem?.let { list.contains(it).isFalse  { leftItem = null } }
                rightItem?.let { list.contains(it).isFalse  { rightItem = null } }
            }

        }
    }

    fun installFeedRule(item: FeedRule)=viewModelScope.launch(Dispatchers.IO) {
        feedRuleDao.insert(item)
    }

    fun isNextID(id: Long): Boolean {
        return rightItem?.id==id
    }

    fun loadAllItemTags(): Flow<List<FeedItemTag>> {
       return  feedItemTagDao.listAll()
    }

    fun checkFeedItemTag(currentItemTags: List<String>) {
        currentItemTags.forEach {tagName->
            checkItemTagExits(tagName)
        }
    }

    fun updateFeedItemTagName(oldName : String, newName : String)=viewModelScope.launch(Dispatchers.IO) {
        feedItemTagDao.updateByName(oldName,newName)
        feedItemTagDao.updateByParentName(oldName,newName)
    }

    fun updateFeedItemTagAttentionLevel(id:Long,attentionLevel:Int)=viewModelScope.launch(Dispatchers.IO) {
        feedItemTagDao.updateFeedItemTagAttentionLevel(id,attentionLevel)
    }

    private fun checkItemTagExits(tagName:String){
        if(tagName != FEED_ITEM_TAG_ROOT_NAME  && !feedItemTagDao.exits(tagName))
            feedItemTagDao.insert(FeedItemTag(name = tagName))
    }

    suspend fun  findSimileTagWithTag(tag :String ): List<String> {
        val tagList= mutableSetOf<String>()
        withContext(Dispatchers.IO){
            feedItemDao.loadSimileTagWithTag(tag).forEach {item-> item.split(',').forEach { tag-> tagList.add(tag) } }
            tagList.remove(tag)
        }
        return tagList.toList()
    }

    fun loadHotItemTags() : Flow<List<FeedItemTag>> {
        return feedItemTagDao.listHotItemTag()
    }

    fun updateItemTag(id: Long, tagsList: List<String>) {
        viewModelScope.launch(Dispatchers.IO){
            feedItemDao.saveItemTag(id,tagsList.joinToString(","))
            checkFeedItemTag(tagsList)
        }
    }

    fun updateFeedItemTagParentTag(itemTag: FeedItemTag, parameterName: String) {
        viewModelScope.launch(Dispatchers.IO){
            checkItemTagExits(parameterName)
            itemTag.parentTag=parameterName
            feedItemTagDao.update(itemTag)
        }
    }

    fun updateFeedItemTagClickCount(id: Long, count: Int) {
        viewModelScope.launch(Dispatchers.IO){
            feedItemTagDao.updateFeedItemTagClickCount(id,count)
        }
    }

    fun getFeedName(feedId: Long): String = runBlocking(Dispatchers.IO){
         feedDao.getFeedName(feedId)
    }
}

/*
class GlobalViewModelFactory : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
        val application = checkNotNull(extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY])
        return GlobalViewModel(application,extras.createSavedStateHandle()) as T
    }
}

fun AppCompatActivity.getGlobalViewModel(): GlobalViewModel {
    return ViewModelProvider(this,GlobalViewModelFactory())[GlobalViewModel::class.java]
}

fun Fragment.getGlobalViewModel(): GlobalViewModel {
    return ViewModelProvider(requireActivity(),GlobalViewModelFactory())[GlobalViewModel::class.java]
}*/
